package com.magicalcoder.lowcode.service.apiopen.service.impl;

import com.magicalcoder.lowcode.anotation.MagicalApiMethod;
import com.magicalcoder.lowcode.anotation.MagicalApiMethodParam;
import com.magicalcoder.lowcode.constant.MagicalLowcodeConstant;
import com.magicalcoder.lowcode.core.common.exception.BusinessException;
import com.magicalcoder.lowcode.core.utils.*;
import com.magicalcoder.lowcode.service.apiopen.dto.McPageData;
import com.magicalcoder.lowcode.service.apiopen.dto.McQuery;
import com.magicalcoder.lowcode.service.apiopen.service.MagicalApiOpenService;
import com.magicalcoder.lowcode.service.apiopen.service.MagicalCoderJpaService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class MagicalCoderJpaServiceImpl implements MagicalCoderJpaService{
    @Resource
    private MagicalApiOpenService magicalApiOpenService;
    @Resource
    private EntityManager entityManager;
    private String parseSql(String sql){
        if (sql.startsWith("\n")){
            sql = sql.substring(1);
        }
        if (sql.endsWith("\n")){
            sql = sql.substring(0,sql.length()-1);
        }
        //用户输入的时候 会出现特殊编码字符串替换掉
        char[] arr = sql.toCharArray();
        for(int i=0;i<arr.length;i++){
            if(arr[i]==160){
                arr[i]=32;//替换为空白符号
            }
        }
        return String.valueOf(arr);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "id",comment = "主键"),
    },doc = "根据主键id获取表实体\njpa.get('t','id值')")
    @Override
    public <T> T get(String tableName, Object id) {
        return get(null,null,tableName,id);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "id",comment = "主键"),
    },doc = "根据主键id获取表实体\njpa.get('c',null,'t','id值')" +
        "")
    @Override
    public <T> T get(String catalog,String schema,String tableName, Object id) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        Object entityId = magicalApiOpenService.translateId(clazz,id);
        return entityManager.find(clazz,entityId);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "id",comment = "主键"),
    },doc = "根据主键id获取表实体\njpa.delete('t','id值')")
    @Override
    public void delete(String tableName, Object id) {
        delete(null,null,tableName,id);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entity",comment = "删除实体",type = "T"),
    },doc = "根据主键id获取表实体\njpa.delete('t','id值')")
    @Override
    public <T> void delete(T entity) {
        entityManager.remove(entityManager.merge(entity));
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "id",comment = "主键"),
    },doc = "根据主键删除实体\njpa.delete('c',null,'t','id值')")
    @Override
    public void delete(String catalog, String schema, String tableName, Object id) {
        Class  clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        Object entityId = magicalApiOpenService.translateId(clazz,id);
        Object entity = magicalApiOpenService.buildEntity(clazz,entityId);
        entityManager.remove(entityManager.merge(entity));
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "参数:null则不作为条件",type = "{}")}
        ,doc = "根据Map删除实体\njpa.remove('c',null,'t',{name:'张三'})")
    @Override
    public int remove(String tableName, Map entity) {
        return remove(null,null,tableName,entity);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entity",comment = "参数:null则不作为条件",type = "T")}
        ,doc = "根据T对象删除实体\njpa.remove('c',null,'t',new T())")
    @Override
    public <T> int remove(T entity) {
        Map<String,Object> param = null;
        try {
            param = CopyUtil.copyToMap(entity, false);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Class clazz = entity.getClass();
        String where = where(param);
        if(StringUtil.isBlank(where)){
            throw new BusinessException(-1,"为了安全期间,未检测到删除语句条件不存在，本次拒绝清库");
        }
        String hql = String.format("DELETE FROM %s %s",clazz.getName(),where);
        return this.updateHql(hql,param);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "参数:null则不作为条件",type = "{}"),
    },doc = "根据Map删除实体\njpa.remove('c',null,'t',{name:'张三'})")
    @Override
    public int remove(String catalog, String schema, String tableName, Map entity) {
        Class  clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        magicalApiOpenService.translateReqParam(entity,clazz,null);
        String where = where(entity);
        if(StringUtil.isBlank(where)){
            throw new BusinessException(-1,"为了安全期间,未检测到删除语句条件不存在，本次拒绝清库");
        }
        String hql = String.format("DELETE FROM %s %s",clazz.getName(),where(entity));
        return this.updateHql(hql,entity);
    }
    private String where(Map<String,Object> entity){
        Set<String> keys = entity.keySet();
        if(keys.size()<=0){
            return "";
        }
        StringBuilder where = new StringBuilder("where ");
        int i=0;
        for(String key:keys){
            if(i!=0){
                where.append(" and ");
            }
            where.append(key).append("=:").append(key);
            i++;
        }
        return where.toString();
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "保存实体不能带主键",type = "{}"),
    },doc = "根据主键id获取表实体,返回新增带主键的实体\njpa.insert('t',{name:''})")
    @Override
    public <T> T insert(String tableName, Map entity) {
        return insert(null,null,tableName,entity);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entity",comment = "保存实体不能带主键",type = "T"),
    },doc = "根据主键id获取表实体,返回新增带主键的实体\njpa.insert(jpa.get('t',1))")
    @Override
    public <T> T insert(T entity) {
        entityManager.persist(entity);
        return entity;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "保存实体不能带主键",type = "{}"),
    },doc = "新增：entity不要带主键，返回保存后带主键的实体\njpa.insert('c',null,'t',{name:''})")
    @Override
    public <T> T insert(String catalog, String schema, String tableName, Map entity) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        String json = GsonUtil.toJson(entity);
        T obj = GsonUtil.toObj(json,clazz);
        entityManager.persist(obj);
        return obj;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "保存实体：不带主键则新增，带主键则更新",type="{}"),
    },doc = "自动保存：如果入参不带主键则新增否则会根据主键更新，返回保存后带主键的实体\njpa.save('t',{id:'xx'name:''})")
    @Override
    public <T> T save(String tableName, Map entity) {
        return save(null,null,tableName,entity);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entity",comment = "保存实体：不带主键则新增，带主键则更新",type = "T"),
    },doc = "自动保存：如果入参不带主键则新增否则会根据主键更新，返回保存后带主键的实体\njpa.save('t',{id:'xx'name:''})")
    @Override
    public <T> T save(T entity) {
        T newEntity = entityManager.merge(entity);
        entityManager.flush();
        return newEntity;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "保存实体：不带主键则新增，带主键则更新",type = "{}"),
    },doc = "自动保存：如果入参不带主键则新增否则会根据主键更新，返回保存后带主键的实体\njpa.save('c',null,'t',{id:MC.uuid(),name:''})")
    @Override
    public <T> T save(String catalog, String schema, String tableName, Map entity) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        String json = GsonUtil.toJson(entity);
        T obj = GsonUtil.toObj(json,clazz);
        //合并实体
        //从库里查出来实体
        T dbEntity = magicalApiOpenService.get(obj);
        if(dbEntity!=null){
            String[] ignoreFields = new ReflectUtil().notExitsFields(entity.keySet(),clazz);
            CopyUtil.copyIgnores(obj,dbEntity,ignoreFields);
        }else {//insert
            dbEntity = obj;
        }
        T newEntity = entityManager.merge(dbEntity);
        entityManager.flush();
        return newEntity;
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "更新实体：必须带主键{id:'xx',name:'xx'}",type = "{}"),
    },doc = "更新实体：根据主键更新传过来的字段值，不传则不更新\njpa.update('t',{id:'',name:''})")
    @Override
    public <T> T update(String tableName, Map entity) {
        return update(null,null,tableName,entity);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entity",comment = "更新实体：必须带主键{id:'xx',name:'xx'}",type = "{}"),
    },doc = "更新实体：根据主键更新传过来的字段值，不传则不更新\njpa.update('c',null,'t',{id:'xx',name:''})")
    @Override
    public <T> T update(String catalog, String schema, String tableName, Map entity) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        String json = GsonUtil.toJson(entity);
        T obj = GsonUtil.toObj(json,clazz);
        //从库里查出来实体
        T dbEntity = magicalApiOpenService.get(obj);
        if(dbEntity==null){
            throw new BusinessException("更新记录不存在");
        }
        //合并实体
        String[] ignoreFields = new ReflectUtil().notExitsFields(entity.keySet(),clazz);
        CopyUtil.copyIgnores(obj,dbEntity,ignoreFields);
        //持久化
        T newEntity = entityManager.merge(dbEntity);
        entityManager.flush();
        return newEntity;//如果是新增 obj有主键 而entity没主键
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entity",comment = "更新实体：必须带主键",type = "T"),
    },doc = "更新实体：实体更新\njpa.update(T)")
    @Override
    public <T> T update(T entity) {
        T dbEntity = magicalApiOpenService.get(entity);
        if(dbEntity==null){
            throw new BusinessException("更新记录不存在");
        }
        //持久化
        T newEntity = entityManager.merge(entity);
        entityManager.flush();
        return newEntity;//如果是新增 obj有主键 而entity没主键
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组:不带主键",type = "[]"),
    },doc = "批量新增：entityList注意不要带主键，返回一组保存的带主键的实体\njpa.batchInsert('t',[{id:'xx',name:''}])")
    @Override
    public <T> List<T> batchInsert(String tableName, List<Map> entityList) {
        return batchInsert(null,null,tableName,entityList);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组",type = "List<T>"),
    },doc = "批量保存")
    @Override
    public <T> List<T> batchInsert(List<T> entityList) {
        List<T> results = new ArrayList();
        if(ListUtil.isNotBlank(entityList)){
            for(T entity:entityList){
                entityManager.persist(entity);
                results.add(entity);
            }
            entityManager.flush();
            entityManager.clear();
        }
        return results;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组：不带主键",type = "[]"),
    },doc = "批量新增：entityList注意不要带主键，返回一组保存的带主键的实体\njpa.batchInsert('c',null,'t',[{name:''},{name:''}])")
    @Override
    public <T> List<T> batchInsert(String catalog, String schema, String tableName, List<Map> entityList) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        List<T> results = new ArrayList();
        if(ListUtil.isNotBlank(entityList)){
            for(Map entity:entityList){
                String json = GsonUtil.toJson(entity);
                T obj = GsonUtil.toObj(json,clazz);
                entityManager.persist(obj);
                results.add(obj);
            }
            entityManager.flush();
            entityManager.clear();
        }
        return results;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组：不带主键则新增否则更新",type = "[]"),
    },type = "List<T>",doc = "批量保存:实体带主键则更新，否则新增，返回一组保存的带主键实体\njpa.batchSave('t',[{id:'xx',name:''}])")
    @Override
    public <T> List<T> batchSave(String tableName, List<Map> entityList) {
        return batchSave(null,null,tableName,entityList);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entityList",comment = "一组实体",type = "List<T>"),
    },doc = "批量保存\njpa.batchSave(list)")
    @Override
    public <T> List<T> batchSave(List<T> entityList) {
        List<T> results = new ArrayList();
        if(ListUtil.isNotBlank(entityList)){
            for(T entity:entityList){
                T newEntity = entityManager.merge(entity);
                results.add(newEntity);
            }
            entityManager.flush();
            entityManager.clear();
        }
        return results;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组",type = "[]"),
    },doc = "批量保存:实体带主键则更新，否则新增，返回一组保存的带主键实体\njpa.batchSave('c',null,'t',[{id:'xx',name:''}])")
    @Override
    public <T> List<T> batchSave(String catalog, String schema, String tableName, List<Map> entityList) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        List<T> results = new ArrayList();
        if(ListUtil.isNotBlank(entityList)){
            for(Map entity:entityList){
                String json = GsonUtil.toJson(entity);
                T obj = GsonUtil.toObj(json,clazz);
                //从库里查出来实体
                T dbEntity = magicalApiOpenService.get(obj);
                if(dbEntity!=null){
                    String[] ignoreFields = new ReflectUtil().notExitsFields(entity.keySet(),clazz);
                    CopyUtil.copyIgnores(obj,dbEntity,ignoreFields);
                }else {
                    dbEntity = obj;
                }
                T newEntity = entityManager.merge(dbEntity);
                results.add(newEntity);
            }
            entityManager.flush();
            entityManager.clear();
        }
        return results;
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "saveList",comment = "保存实体数组",type = "[]"),
        @MagicalApiMethodParam(name = "deleteList",comment = "删除实体数组",type = "[]"),
    },doc = "批量删除后再保存:实体带主键则更新，否则新增，返回一组保存的带主键实体\njpa.batchSave('t',[{id:'xx',name:''}],[{id:'xx',name:''}])")
    @Override
    public <T> List<T> batchDeleteAndSave(String tableName, List<Map> saveList, List<Map> deleteList) {
        List<T> list = null;
        if(ListUtil.isNotBlank(deleteList)){
            Class<T> clazz = magicalApiOpenService.scannerClass(null,null,tableName);
            for(Map entity:deleteList){
                String json = GsonUtil.toJson(entity);
                T obj = GsonUtil.toObj(json,clazz);
                entityManager.remove(entityManager.merge(obj));
            }
            entityManager.flush();
            entityManager.clear();
        }
        if(ListUtil.isNotBlank(saveList)){
            list = batchSave(null,null,tableName,saveList);
        }
        return list;
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组",type = "[]"),
    },doc = "批量删除后再保存:实体带主键则更新，否则新增，返回一组保存的带主键实体\njpa.batchSave('c',null,'t',[{id:'xx',name:''}],[{id:'xx',name:''}])")
    @Override
    public <T> List<T> batchDeleteAndSave(String catalog, String schema, String tableName, List<Map> saveList, List<Map> deleteList) {
        List<T> list = null;
        if(ListUtil.isNotBlank(deleteList)){
            Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
            for(Map entity:deleteList){
                String json = GsonUtil.toJson(entity);
                T obj = GsonUtil.toObj(json,clazz);
                entityManager.remove(entityManager.merge(obj));
            }
            entityManager.flush();
            entityManager.clear();
        }
        if(ListUtil.isNotBlank(saveList)){
            list = batchSave(catalog,schema,tableName,saveList);
        }
        return list;
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "entityList",comment = "实体数组",type = "[]"),
    },doc = "批量更新:实体带主键则更新，否则抛出异常，返回一组保存的带主键实体\njpa.batchUpdate('c',null,'t',[{id:'xx',name:''}])")
    @Override
    public <T> List<T> batchUpdate(String catalog, String schema, String tableName, List<Map> entityList) {
        Class<T> clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        List<T> results = new ArrayList();
        if(ListUtil.isNotBlank(entityList)){
            for(Map entity:entityList){
                String json = GsonUtil.toJson(entity);
                T obj = GsonUtil.toObj(json,clazz);
                //从库里查出来实体
                T dbEntity = magicalApiOpenService.get(obj);
                if(dbEntity!=null){
                    String[] ignoreFields = new ReflectUtil().notExitsFields(entity.keySet(),clazz);
                    CopyUtil.copyIgnores(obj,dbEntity,ignoreFields);
                }else {
                    throw new BusinessException(-1,"存在缺少主键");
                }
                T newEntity = entityManager.merge(dbEntity);
                results.add(newEntity);
            }
            entityManager.flush();
            entityManager.clear();
        }
        return results;
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "ids",comment = "主键数组",type = "[]"),
    },doc = "批量删除\njpa.batchDelete('t',['id值1','id值2'])")
    @Override
    public void batchDelete(String tableName, List<Object> ids) {
        if(ListUtil.isNotBlank(ids)){
            for(Object id:ids){
                delete(tableName,id);
            }
            entityManager.flush();
            entityManager.clear();
        }
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "entityList",comment = "一组实体",type = "List<T>"),
    },doc = "批量删除\njpa.batchDelete(list)")
    @Override
    public <T> void batchDelete(List<T> entityList) {
        if(ListUtil.isNotBlank(entityList)){
            for(T entity:entityList){
                entityManager.remove(entity);
            }
            entityManager.flush();
            entityManager.clear();
        }
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "ids",comment = "主键数组",type = "[]"),
    },doc = "批量删除\njpa.batchDelete('c',null,'t',['id值1','id值2'])")
    @Override
    public void batchDelete(String catalog, String schema, String tableName, List<Object> ids) {
        if(ListUtil.isNotBlank(ids)){
            for(Object id:ids){
                delete(catalog,schema,tableName,id);
            }
            entityManager.flush();
            entityManager.clear();
        }
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数：严格校验"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
        @MagicalApiMethodParam(name = "page",comment = "页码"),
        @MagicalApiMethodParam(name = "limit",comment = "返回条数"),
    },doc = "获取一组数据：严格校验mcQuery\njpa.find('t',{param:{id:1}},1,10)")
    @Override
    public <T> List<T> find(String tableName, Map<String, Object> mcQuery,Integer page,Integer limit) {
        return find(null,null,tableName,mcQuery,page,limit);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数:严格校验"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
        @MagicalApiMethodParam(name = "page",comment = "页码"),
        @MagicalApiMethodParam(name = "limit",comment = "返回条数"),
    },doc = "获取一组数据：严格校验mcQuery\njpa.find('c',null,'t',{param:{id:1}},1,10)\njpa.find('c',null,'t',{param:{id:1}},null,null)")
    @Override
    public <T> List<T> find(String catalog, String schema, String tableName, Map<String, Object> mcQuery,Integer page,Integer limit) {
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        McQuery query =magicalApiOpenService.toMcQuery(null,clazz,mcQuery,page,limit);
        return magicalApiOpenService.queryList(clazz,query);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数:不校验"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
    },doc = "获取一组数据\njpa.find('t',{param:{id:1},condition:{id:'='}})")
    @Override
    public <T> List<T> find(String tableName, Map<String, Object> mcQuery) {
        return find(null,null,tableName,mcQuery);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数:不校验"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
    },doc = "获取一组数据\njpa.find('c',null,'t',{param:{id:1}},1,10)")
    @Override
    public <T> List<T> find(String catalog, String schema, String tableName, Map<String, Object> mcQuery) {
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        McQuery query = GsonUtil.toObj(GsonUtil.toJson(mcQuery),McQuery.class);
        return magicalApiOpenService.queryList(clazz,query);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
        @MagicalApiMethodParam(name = "page",comment = "页码"),
        @MagicalApiMethodParam(name = "limit",comment = "返回条数"),
    },doc = "获取分页数据:必须按照mcQuery对象传\njpa.pager('t',{param:{id:1}},1,10)")
    @Override
    public <T> McPageData<T> pager(String tableName, Map<String, Object> mcQuery,Integer page,Integer limit) {
        return pager(null,null,tableName,mcQuery,page,limit);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
        @MagicalApiMethodParam(name = "page",comment = "页码"),
        @MagicalApiMethodParam(name = "limit",comment = "返回条数"),
    },doc = "获取分页数据:必须按照mcQuery对象传\njpa.pager('c',null,'t',{param:{id:1}},1,10)")
    @Override
    public <T> McPageData<T> pager(String catalog, String schema, String tableName, Map<String, Object> mcQuery,Integer page,Integer limit) {
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        McQuery query =magicalApiOpenService.toMcQuery(null,clazz,mcQuery,page,limit);
        return magicalApiOpenService.queryPageData(clazz,query);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
    },doc = "获取分页数据:不校验mcQuery对象\njpa.pager('t',{page:1,limit:10,param:{id:1}})")
    @Override
    public <T> McPageData<T> pager(String tableName, Map<String, Object> mcQuery) {
        return pager(null,null,tableName,mcQuery);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "catalog",comment = "目录"),
        @MagicalApiMethodParam(name = "schema",comment = "模式"),
        @MagicalApiMethodParam(name = "tableName",comment = "表名"),
        @MagicalApiMethodParam(name = "mcQuery",type = "{}",comment = "查询参数"+ MagicalLowcodeConstant.MC_QUERY_DEMO+MagicalLowcodeConstant.MC_QUERY_COMMENT),
    },doc = "获取分页数据:不校验mcQuery对象\njpa.pager('c',null,'t',{page:1,limit:10,param:{id:1}})")
    @Override
    public <T> McPageData<T> pager(String catalog, String schema, String tableName, Map<String, Object> mcQuery) {
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        McQuery query = GsonUtil.toObj(GsonUtil.toJson(mcQuery),McQuery.class);
        return magicalApiOpenService.queryPageData(clazz,query);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "hql",comment = "hql语句"),
        @MagicalApiMethodParam(name = "query",type = "{}",comment = "查询参数"),
    },doc = "根据hql查询，注意不是sql。\njpa.findHql(hql,{id:1})")
    @Override
    public List findHql(String hql, Map<String, Object> query) {
        return findHql(hql,query,null,null);
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "hql",comment = "hql语句"),
        @MagicalApiMethodParam(name = "query",type = "{}",comment = "查询参数"),
    },doc = "根据hql查询个数select count()，注意不是sql。\njpa.countHql(hql,{id:1})")
    @Override
    public long countHql(String hql, Map<String, Object> query) {
        TypedQuery<Long> qt = entityManager.createQuery(parseSql(hql),Long.class);
        if(query!=null && !query.isEmpty()){
            for(String key:query.keySet()){
                Object value = query.get(key);
                qt.setParameter(key,value);
            }
        }
        return qt.getSingleResult().longValue();
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "hql",comment = "hql语句"),
        @MagicalApiMethodParam(name = "query",type = "{}",comment = "查询参数"),
    },doc = "根据hql更新(delete update)，注意不是sql。\njpa.updateHql(hql,{id:1})")
    @Override
    public int updateHql(String hql, Map<String, Object> query) {
        Query qt = entityManager.createQuery(parseSql(hql));
        if(query!=null && !query.isEmpty()){
            for(String key:query.keySet()){
                Object value = query.get(key);
                qt.setParameter(key,value);
            }
        }
        return qt.executeUpdate();
    }

    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "hql",comment = "hql语句"),
        @MagicalApiMethodParam(name = "query",type = "{}",comment = "查询参数"),
        @MagicalApiMethodParam(name = "page",comment = "页码"),
        @MagicalApiMethodParam(name = "limit",comment = "返回多少条"),
    },doc = "根据hql查询，注意不是sql\njpa.findHql(hql,{id:1},1,10)")
    @Override
    public List findHql(String hql, Map<String, Object> query, Integer page, Integer limit) {
        Query qt = entityManager.createQuery(parseSql(hql));
        if(query!=null && !query.isEmpty()){
            for(String key:query.keySet()){
                Object value = query.get(key);
                qt.setParameter(key,value);
            }
        }
        if(limit!=null){
            if(page!=null){
                qt.setFirstResult((page-1)*limit);
            }
            if(limit!=null){
                qt.setMaxResults(limit);
            }
        }
        List list = qt.getResultList();
        return list;
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "hql",comment = "hql语句"),
        @MagicalApiMethodParam(name = "query",type = "{}",comment = "查询参数"),
    },doc = "根据hql查询，注意不是sql。\njpa.pagerHql(hql,{id:1})")
    @Override
    public <T> McPageData<T> pagerHql(String hql, Map<String, Object> query) {
        return pagerHql(hql,query,null,null);
    }
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "hql",comment = "hql语句"),
        @MagicalApiMethodParam(name = "query",type = "{}",comment = "查询参数"),
        @MagicalApiMethodParam(name = "page",comment = "页码"),
        @MagicalApiMethodParam(name = "limit",comment = "返回多少条"),
    },doc = "根据hql查询，注意不是sql\njpa.pagerHql(hql,{id:1},1,10)")
    @Override
    public <T> McPageData<T> pagerHql(String hql, Map<String, Object> query, Integer page, Integer limit) {
        List list = findHql(hql,query,page,limit);
        //查询个数的
        int index = hql.toUpperCase().indexOf("FROM");
        String countSql = "select count(*) " +hql.substring(index);
        TypedQuery<Long> queryCount = entityManager.createQuery(parseSql(countSql),Long.class);
        if(query!=null && !query.isEmpty()){
            for(String key:query.keySet()){
                Object value = query.get(key);
                queryCount.setParameter(key,value);
            }
        }
        McPageData mcPageData = new McPageData(Integer.valueOf(queryCount.getSingleResult().toString()),list);
        return mcPageData;
    }

    @Override
    public Map<String, Object> removeParentChildren(Map<String, Object> parent) {
        Map<String,String> info = (Map<String,String>)parent.get("_info");
        String catalog = info.get("catalog"),
            schema=info.get("schema"),
            table = info.get("table");
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,table);
        String json = GsonUtil.toJson(parent);
        Object obj = GsonUtil.toObj(json,clazz);
        magicalApiOpenService.remove(obj);
        Object id = magicalApiOpenService.pkValue(obj);
        if(id==null){
            return null;
        }
        List<Map<String,Object>> children = (List<Map<String,Object>>) parent.get("_children");
        if(ListUtil.isNotBlank(children)){
            for(Map<String,Object> child:children){
                Map<String,String> cinfo = (Map<String,String>)child.get("_info");
                String childCatalog = cinfo.get("catalog");
                String childSchema = cinfo.get("schema");
                String childTable = cinfo.get("table");
                String pidName = cinfo.get("pidName");
                remove(childCatalog,childSchema,childTable,MapUtil.buildMap(pidName,id));
            }
        }

        return null;
    }

    /**
     * 保存父子详情页数据
     * @param parent {id,name,_info:{catalog,schema,table},_children:[{_info:{catalog,schema,table},id,name}]}
     */
    @MagicalApiMethod(value = {
        @MagicalApiMethodParam(name = "parent",type = "{}",comment = "{id,name,_info:{catalog,schema,table},_children:[{_info:{catalog,schema,table,pidName},saveList:[],deleteList:[]}]}"),
    },doc = "保存父子详情页数据：_info代表实体表信息,_children代表子表数据集pidName:此字段名将被设置父亲主键值" +
        "\njpa.saveParentChildren({id:1,name:'',_info:{catalog:'c',schema:null,table:'t'},_children:[{_info:{catalog:'c',schema:null,table:'t',pidName:'parentId'},saveList:[],deleteList:[]}]})")
    @Override
    public Map<String,Object> saveParentChildren(Map<String,Object> parent) {
        Map<String,String> info = (Map)parent.get("_info");

        String catalog = info.get("catalog"),
            schema=info.get("schema"),
            table = info.get("table");
        Object parentEntity = save(catalog,schema,table,parent);
        Object pid = magicalApiOpenService.pkValue(parentEntity);

        List<Map> children = (List<Map>)parent.get("_children");//总共多少子表
        if(ListUtil.isNotBlank(children)){
            for(Map child:children){
                Map<String,String> cinfo = (Map)child.get("_info");
                if(cinfo==null){
                    continue;
                }
                String childCatalog = cinfo.get("catalog");
                String childSchema = cinfo.get("schema");
                String childTable = cinfo.get("table");
                if(StringUtil.isBlank(childTable)){
                    throw new BusinessException("子表_children._info.table不能为空");
                }
                String pidName = cinfo.get("pidName");//父亲字段名称
                if(StringUtil.isBlank(pidName)){
                    throw new BusinessException("pidName不能为空");
                }
                Class childClass = magicalApiOpenService.scannerClass(childCatalog,childSchema,childTable);
                String childPk = magicalApiOpenService.pkName(childClass);
                List<Map> deleteList = (List<Map>)child.get("deleteList");
                if(ListUtil.isNotBlank(deleteList)){
                    deleteList.forEach((entity)->{
                        Object childId = magicalApiOpenService.translateId(childClass,entity.get(childPk));
                        delete(childCatalog,childSchema,childTable,childId);
                    });
                }
                List<Map> list = (List<Map>)child.get("saveList");
                if(ListUtil.isNotBlank(list)){
                    list.forEach((entity)->{
                        entity.put(pidName,pid);//存储父亲字段值
                        save(childCatalog,childSchema,childTable,entity);
                    });
                }

            }
        }
        return MapUtil.buildMap("id",pid);

    }


}
